/*
 * Copyright (C) 2017 Spreadtrum Communications Inc.
 *
 * This software is licensed under the terms of the GNU General Public
 * License version 2, as published by the Free Software Foundation, and
 * may be copied, distributed, and modified under those terms.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#include "sprd_panel.h"
#include "sprd_dsi.h"
#include "dsi/mipi_dsi_api.h"
#include "sprd_dphy.h"
#include <i2c.h>

static uint8_t init_data[] = {
	0x23, 0x00, 0x00, 0x02, 0xFE, 0x0E,
	0x23, 0x00, 0x00, 0x02, 0x4B, 0x00,
	0x23, 0x00, 0x00, 0x02, 0x4C, 0x0F,
	0x23, 0x00, 0x00, 0x02, 0x4D, 0x20,
	0x23, 0x00, 0x00, 0x02, 0x4E, 0x40,
	0x23, 0x00, 0x00, 0x02, 0x4F, 0x60,
	0x23, 0x00, 0x00, 0x02, 0x50, 0xA0,
	0x23, 0x00, 0x00, 0x02, 0x51, 0xC0,
	0x23, 0x00, 0x00, 0x02, 0x52, 0xE0,
	0x23, 0x00, 0x00, 0x02, 0x53, 0xFF,

	0x23, 0x00, 0x00, 0x02, 0xFE, 0x0D,
	0x23, 0x00, 0x00, 0x02, 0x08, 0x41,
	0x23, 0x00, 0x00, 0x02, 0x46, 0x02,
	0x23, 0x00, 0x00, 0x02, 0x72, 0x09,
	0x23, 0x00, 0x00, 0x02, 0x1E, 0x04,
	0x23, 0x00, 0x00, 0x02, 0x1E, 0x00,

	0x23, 0x00, 0x00, 0x02, 0xFE, 0x0A,
	0x23, 0x00, 0x00, 0x02, 0x24, 0x17,
	0x23, 0x00, 0x00, 0x02, 0x04, 0x07,
	0x23, 0x00, 0x00, 0x02, 0x1A, 0x0C,

	0x23, 0x00, 0x00, 0x02, 0xFE, 0x04,
	0x23, 0x00, 0x00, 0x02, 0x00, 0x0C,
	0x23, 0x00, 0x00, 0x02, 0x05, 0x10,		//V3.13 VFPDA = 10h
	0x23, 0x00, 0x00, 0x02, 0x06, 0x08,		//V3.12
	0x23, 0x00, 0x00, 0x02, 0x08, 0x10,		//V3.13 VFPDB = 10h
	0x23, 0x00, 0x00, 0x02, 0x09, 0x08,		//V3.12
	0x23, 0x00, 0x00, 0x02, 0x0A, 0xE6,
	0x23, 0x00, 0x00, 0x02, 0x0B, 0x8C,
	0x23, 0x00, 0x00, 0x02, 0x1A, 0x12,
//	0x23, 0x00, 0x00, 0x02, 0x1E, 0xE0,		//V3.12 ESD disable Video mode
	0x23, 0x00, 0x00, 0x02, 0x29, 0x93,
	0x23, 0x00, 0x00, 0x02, 0x2A, 0x93,
	0x23, 0x00, 0x00, 0x02, 0x2F, 0x02,
	0x23, 0x00, 0x00, 0x02, 0x31, 0x02,
	0x23, 0x00, 0x00, 0x02, 0x33, 0x05,
	0x23, 0x00, 0x00, 0x02, 0x37, 0x2D,
	0x23, 0x00, 0x00, 0x02, 0x38, 0x2D,
	0x23, 0x00, 0x00, 0x02, 0x3A, 0x1E,
	0x23, 0x00, 0x00, 0x02, 0x3B, 0x1E,
	0x23, 0x00, 0x00, 0x02, 0x3D, 0x27,
	0x23, 0x00, 0x00, 0x02, 0x3F, 0x80,
	0x23, 0x00, 0x00, 0x02, 0x40, 0x40,
	0x23, 0x00, 0x00, 0x02, 0x41, 0xE0,
	0x23, 0x00, 0x00, 0x02, 0x4F, 0x2F,
	0x23, 0x00, 0x00, 0x02, 0x50, 0x1E,

	0x23, 0x00, 0x00, 0x02, 0xFE, 0x06,
	0x23, 0x00, 0x00, 0x02, 0x00, 0xEC,
	0x23, 0x00, 0x00, 0x02, 0x05, 0x06,
	0x23, 0x00, 0x00, 0x02, 0x07, 0xA2,
	0x23, 0x00, 0x00, 0x02, 0x08, 0xEC,
	0x23, 0x00, 0x00, 0x02, 0x0D, 0x04,
	0x23, 0x00, 0x00, 0x02, 0x0F, 0xA2,
	0x23, 0x00, 0x00, 0x02, 0x32, 0xEC,
	0x23, 0x00, 0x00, 0x02, 0x37, 0x07,
	0x23, 0x00, 0x00, 0x02, 0x39, 0x83,
	0x23, 0x00, 0x00, 0x02, 0x3A, 0xEC,
	0x23, 0x00, 0x00, 0x02, 0x41, 0x06,
	0x23, 0x00, 0x00, 0x02, 0x43, 0x83,
	0x23, 0x00, 0x00, 0x02, 0x44, 0xEC,
	0x23, 0x00, 0x00, 0x02, 0x49, 0x06,
	0x23, 0x00, 0x00, 0x02, 0x4B, 0xA2,
	0x23, 0x00, 0x00, 0x02, 0x4C, 0xEC,
	0x23, 0x00, 0x00, 0x02, 0x51, 0x04,
	0x23, 0x00, 0x00, 0x02, 0x53, 0xA2,
	0x23, 0x00, 0x00, 0x02, 0x75, 0xEC,
	0x23, 0x00, 0x00, 0x02, 0x7A, 0x07,
	0x23, 0x00, 0x00, 0x02, 0x7C, 0x83,
	0x23, 0x00, 0x00, 0x02, 0x7D, 0xEC,
	0x23, 0x00, 0x00, 0x02, 0x82, 0x06,
	0x23, 0x00, 0x00, 0x02, 0x84, 0x83,
	0x23, 0x00, 0x00, 0x02, 0x85, 0xEC,
	0x23, 0x00, 0x00, 0x02, 0x86, 0x0F,
	0x23, 0x00, 0x00, 0x02, 0x87, 0xFF,
	0x23, 0x00, 0x00, 0x02, 0x88, 0x00,
	0x23, 0x00, 0x00, 0x02, 0x8A, 0x02,
	0x23, 0x00, 0x00, 0x02, 0x8C, 0xA2,
	0x23, 0x00, 0x00, 0x02, 0x8D, 0xEE,		//VSR18 V3.10 enable VSR Vrst , V3.12 ESD V-rst
	0x23, 0x00, 0x00, 0x02, 0x8E, 0x01,		//VSR18
	0x23, 0x00, 0x00, 0x02, 0x8F, 0xE8,		//VSR18
	0x23, 0x00, 0x00, 0x02, 0x90, 0x0A,		//VSR18
	0x23, 0x00, 0x00, 0x02, 0x92, 0x06,		//VSR18
	0x23, 0x00, 0x00, 0x02, 0x93, 0xA0,		//VSR18
	0x23, 0x00, 0x00, 0x02, 0x94, 0xA8,		//VSR18
	0x23, 0x00, 0x00, 0x02, 0x95, 0xEC,
	0x23, 0x00, 0x00, 0x02, 0x96, 0x0F,
	0x23, 0x00, 0x00, 0x02, 0x97, 0xFF,
	0x23, 0x00, 0x00, 0x02, 0x98, 0x00,
	0x23, 0x00, 0x00, 0x02, 0x9A, 0x02,
	0x23, 0x00, 0x00, 0x02, 0x9C, 0xA2,
	0x23, 0x00, 0x00, 0x02, 0xA6, 0x21,
	0x23, 0x00, 0x00, 0x02, 0xA7, 0x05,
	0x23, 0x00, 0x00, 0x02, 0xA9, 0x06,
	0x23, 0x00, 0x00, 0x02, 0xAC, 0x04,		//control VSTE
	0x23, 0x00, 0x00, 0x02, 0xB1, 0x12,
	0x23, 0x00, 0x00, 0x02, 0xB2, 0x17,
	0x23, 0x00, 0x00, 0x02, 0xB3, 0x17,
	0x23, 0x00, 0x00, 0x02, 0xB4, 0x17,
	0x23, 0x00, 0x00, 0x02, 0xB5, 0x17,
	0x23, 0x00, 0x00, 0x02, 0xB6, 0x11,		// VSR20->VSR18
	0x23, 0x00, 0x00, 0x02, 0xB7, 0x08,
	0x23, 0x00, 0x00, 0x02, 0xB8, 0x09,
	0x23, 0x00, 0x00, 0x02, 0xB9, 0x06,
	0x23, 0x00, 0x00, 0x02, 0xBA, 0x07,
	0x23, 0x00, 0x00, 0x02, 0xBB, 0x17,
	0x23, 0x00, 0x00, 0x02, 0xBC, 0x17,
	0x23, 0x00, 0x00, 0x02, 0xBD, 0x17,
	0x23, 0x00, 0x00, 0x02, 0xBE, 0x17,
	0x23, 0x00, 0x00, 0x02, 0xBF, 0x17,
	0x23, 0x00, 0x00, 0x02, 0xC0, 0x17,
	0x23, 0x00, 0x00, 0x02, 0xC1, 0x17,
	0x23, 0x00, 0x00, 0x02, 0xC2, 0x17,
	0x23, 0x00, 0x00, 0x02, 0xC3, 0x17,
	0x23, 0x00, 0x00, 0x02, 0xC4, 0x0F,
	0x23, 0x00, 0x00, 0x02, 0xC5, 0x0E,
	0x23, 0x00, 0x00, 0x02, 0xC6, 0x00,
	0x23, 0x00, 0x00, 0x02, 0xC7, 0x01,
	0x23, 0x00, 0x00, 0x02, 0xC8, 0x10,

	0x23, 0x00, 0x00, 0x02, 0xFE, 0x00,
	0x23, 0x00, 0x00, 0x02, 0xC2, 0x03,//0x03:video mode 0x08:cmd mode
	0x23, 0x00, 0x00, 0x02, 0x35, 0x00,
	0x29, 0x00, 0x00, 0x03, 0x44, 0x03, 0x80,		//V3.10 modify TE position
	0x13, 0x78, 0x00, 0x01, 0x11,//Delay 120

	0x13, 0x64, 0x00, 0x01, 0x29,
	CMD_END
};

static int mipi_dsi_send_cmds(struct sprd_dsi *dsi, void *data)
{
	uint16_t len;
	struct dsi_cmd_desc *cmds = data;

	if ((cmds == NULL) || (dsi == NULL))
		return -1;

	for (; cmds->data_type != CMD_END;) {
		len = (cmds->wc_h << 8) | cmds->wc_l;
		mipi_dsi_gen_write(dsi, cmds->payload, len);
		if (cmds->wait)
			msleep(cmds->wait);
		cmds = (struct dsi_cmd_desc *)(cmds->payload + len);
	}
	return 0;
}

static int rm67191_init(void)
{
	struct sprd_dsi *dsi = &dsi_device;
	struct sprd_dphy *dphy = &dphy_device;

	mipi_dsi_lp_cmd_enable(dsi, true);
	mipi_dsi_send_cmds(dsi, init_data);
	mipi_dsi_set_work_mode(dsi, SPRD_MIPI_MODE_VIDEO);
	mipi_dsi_state_reset(dsi);
	mipi_dphy_hs_clk_en(dphy, true);

	return 0;
}

static int rm67191_readid(void)
{
	struct sprd_dsi *dsi = &dsi_device;
	uint8_t read_buf[4] = {0};

	mipi_dsi_lp_cmd_enable(dsi, true);
	mipi_dsi_set_max_return_size(dsi, 3);
	mipi_dsi_dcs_read(dsi, 0x04, read_buf, 3);

	if((0x67 == read_buf[0]) && (0xED == read_buf[1]) && (0x0B == read_buf[2])) {
		pr_info("rm67191 read id success!\n");
		return 0;
        }

	pr_err("rm67191 read id failed!\n");
	return -1;
}

static int rm67191_power(int on)
{
	if (on) {
		sprd_gpio_request(NULL, CONFIG_LCM_GPIO_AVDDEN);
		sprd_gpio_direction_output(NULL, CONFIG_LCM_GPIO_AVDDEN, 1);
		mdelay(10);

		sprd_gpio_request(NULL, CONFIG_LCM_GPIO_RSTN);
		sprd_gpio_direction_output(NULL, CONFIG_LCM_GPIO_RSTN, 1);
		mdelay(5);
		sprd_gpio_direction_output(NULL, CONFIG_LCM_GPIO_RSTN, 0);
		mdelay(5);
		sprd_gpio_direction_output(NULL, CONFIG_LCM_GPIO_RSTN, 1);
		mdelay(20);
	} else {
		sprd_gpio_direction_output(NULL, CONFIG_LCM_GPIO_RSTN, 0);
		mdelay(5);
	}

	return 0;
}

static struct panel_ops rm67191_ops = {
	.init = rm67191_init,
	.read_id = rm67191_readid,
	.power = rm67191_power,
};

static struct panel_info rm67191_info = {
	/* common parameters */
	.lcd_name = "lcd_rm67191_edo_mipi_fhd",
	.type = SPRD_PANEL_TYPE_MIPI,
	.bpp = 24,
//	.fps = 60,
	.width = 1080,
	.height = 1920,

	/* DPI specific parameters */
	.pixel_clk = 153600000, /*Hz*/
	.rgb_timing = {
		.hfp = 169,
		.hbp = 36,
		.hsync = 2,
		.vfp = 32,
		.vbp = 32,
		.vsync = 4,
	},

	/* MIPI DSI specific parameters */
	.phy_freq = 9798*100,
	.lane_num = 4,
	.work_mode = SPRD_MIPI_MODE_VIDEO,
	.burst_mode = PANEL_VIDEO_BURST_MODE,
	.nc_clk_en = false,
};

struct panel_driver rm67191_edo_driver = {
	.info = &rm67191_info,
	.ops = &rm67191_ops,
};
